home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / rshd / rshd.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-22  |  18.2 KB  |  823 lines

  1. /*-
  2.  * Copyright (c) 1988, 1989, 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)rshd.c    8.2 (Berkeley) 4/6/94";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * remote shell server:
  46.  *    [port]\0
  47.  *    remuser\0
  48.  *    locuser\0
  49.  *    command\0
  50.  *    data
  51.  */
  52.  
  53. #ifdef HAVE_CONFIG_H
  54. #include <config.h>
  55. #endif
  56.  
  57. #include <sys/param.h>
  58. #include <sys/ioctl.h>
  59. #include <sys/time.h>
  60. #include <sys/socket.h>
  61.  
  62. #include <netinet/in.h>
  63. #include <arpa/inet.h>
  64. #include <netdb.h>
  65.  
  66. #include <errno.h>
  67. #include <fcntl.h>
  68. #include <paths.h>
  69. #include <pwd.h>
  70. #include <signal.h>
  71. #include <stdio.h>
  72. #include <stdlib.h>
  73. #include <string.h>
  74. #include <syslog.h>
  75. #include <unistd.h>
  76. #include <getopt.h>
  77.  
  78. int    keepalive = 1;
  79. int    check_all;
  80. int    log_success;        /* If TRUE, log all successful accesses */
  81. int    sent_null;
  82.  
  83. void     doit __P((struct sockaddr_in *));
  84. void     error __P((const char *, ...));
  85. char    *getstr __P((char *));
  86. int     local_domain __P((char *));
  87. char    *topdomain __P((char *));
  88. void     usage __P((void));
  89.  
  90. #ifdef    KERBEROS
  91. #include <kerberosIV/des.h>
  92. #include <kerberosIV/krb.h>
  93. #define    VERSION_SIZE    9
  94. #define SECURE_MESSAGE  "This rsh session is using DES encryption for all transmissions.\r\n"
  95. #define    OPTIONS        "alnkvxL"
  96. char    authbuf[sizeof(AUTH_DAT)];
  97. char    tickbuf[sizeof(KTEXT_ST)];
  98. int    doencrypt, use_kerberos, vacuous;
  99. Key_schedule    schedule;
  100. #else
  101. #define    OPTIONS    "alnL"
  102. #endif
  103.  
  104. int
  105. main(argc, argv)
  106.     int argc;
  107.     char *argv[];
  108. {
  109.     extern int __check_rhosts_file;
  110.     struct linger linger;
  111.     int ch, on = 1, fromlen;
  112.     struct sockaddr_in from;
  113.  
  114.     openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  115.  
  116.     opterr = 0;
  117.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  118.         switch (ch) {
  119.         case 'a':
  120.             check_all = 1;
  121.             break;
  122.         case 'l':
  123.             __check_rhosts_file = 0;
  124.             break;
  125.         case 'n':
  126.             keepalive = 0;
  127.             break;
  128. #ifdef    KERBEROS
  129.         case 'k':
  130.             use_kerberos = 1;
  131.             break;
  132.  
  133.         case 'v':
  134.             vacuous = 1;
  135.             break;
  136.  
  137. #ifdef CRYPT
  138.         case 'x':
  139.             doencrypt = 1;
  140.             break;
  141. #endif
  142. #endif
  143.         case 'L':
  144.             log_success = 1;
  145.             break;
  146.         case '?':
  147.         default:
  148.             usage();
  149.             break;
  150.         }
  151.  
  152.     argc -= optind;
  153.     argv += optind;
  154.  
  155. #ifdef    KERBEROS
  156.     if (use_kerberos && vacuous) {
  157.         syslog(LOG_ERR, "only one of -k and -v allowed");
  158.         exit(2);
  159.     }
  160. #ifdef CRYPT
  161.     if (doencrypt && !use_kerberos) {
  162.         syslog(LOG_ERR, "-k is required for -x");
  163.         exit(2);
  164.     }
  165. #endif
  166. #endif
  167.  
  168.     fromlen = sizeof (from);
  169.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  170.         syslog(LOG_ERR, "getpeername: %m");
  171.         _exit(1);
  172.     }
  173.     if (keepalive &&
  174.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  175.         sizeof(on)) < 0)
  176.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  177.     linger.l_onoff = 1;
  178.     linger.l_linger = 60;            /* XXX */
  179.     if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
  180.         sizeof (linger)) < 0)
  181.         syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  182.     doit(&from);
  183.     /* NOTREACHED */
  184. }
  185.  
  186. char    username[20] = "USER=";
  187. char    homedir[64] = "HOME=";
  188. char    shell[64] = "SHELL=";
  189. char    path[100] = "PATH=";
  190. char    *envinit[] =
  191.         {homedir, shell, path, username, 0};
  192. char    **environ;
  193.  
  194. void
  195. doit(fromp)
  196.     struct sockaddr_in *fromp;
  197. {
  198.     extern char *__rcmd_errstr;    /* syslog hook from libc/net/rcmd.c. */
  199.     struct hostent *hp;
  200.     struct passwd *pwd;
  201.     u_short port;
  202.     fd_set ready, readfrom;
  203.     int cc, nfd, pv[2], pid, s;
  204.     int one = 1;
  205.     char *hostname, *errorstr, *errorhost;
  206.     char *cp, sig, buf[BUFSIZ];
  207.     char *cmdbuf, *locuser, *remuser;
  208.  
  209. #ifdef    KERBEROS
  210.     AUTH_DAT    *kdata = (AUTH_DAT *) NULL;
  211.     KTEXT        ticket = (KTEXT) NULL;
  212.     char        instance[INST_SZ], version[VERSION_SIZE];
  213.     struct        sockaddr_in    fromaddr;
  214.     int        rc;
  215.     long        authopts;
  216.     int        pv1[2], pv2[2];
  217.     fd_set        wready, writeto;
  218.  
  219.     fromaddr = *fromp;
  220. #endif
  221.  
  222.     (void) signal(SIGINT, SIG_DFL);
  223.     (void) signal(SIGQUIT, SIG_DFL);
  224.     (void) signal(SIGTERM, SIG_DFL);
  225. #ifdef DEBUG
  226.     { int t = open(_PATH_TTY, 2);
  227.       if (t >= 0) {
  228.         ioctl(t, TIOCNOTTY, (char *)0);
  229.         (void) close(t);
  230.       }
  231.     }
  232. #endif
  233.     fromp->sin_port = ntohs((u_short)fromp->sin_port);
  234.     if (fromp->sin_family != AF_INET) {
  235.         syslog(LOG_ERR, "malformed \"from\" address (af %d)\n",
  236.             fromp->sin_family);
  237.         exit(1);
  238.     }
  239. #ifdef IP_OPTIONS
  240.       {
  241.     u_char optbuf[BUFSIZ/3], *cp;
  242.     char lbuf[BUFSIZ], *lp;
  243.     int optsize = sizeof(optbuf), ipproto;
  244.     struct protoent *ip;
  245.  
  246.     if ((ip = getprotobyname("ip")) != NULL)
  247.         ipproto = ip->p_proto;
  248.     else
  249.         ipproto = IPPROTO_IP;
  250.     if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
  251.         optsize != 0) {
  252.         lp = lbuf;
  253.         for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
  254.             sprintf(lp, " %2.2x", *cp);
  255.         syslog(LOG_NOTICE,
  256.             "Connection received from %s using IP options (ignored):%s",
  257.             inet_ntoa(fromp->sin_addr), lbuf);
  258.         if (setsockopt(0, ipproto, IP_OPTIONS,
  259.             (char *)NULL, optsize) != 0) {
  260.             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
  261.             exit(1);
  262.         }
  263.     }
  264.       }
  265. #endif
  266.  
  267. #ifdef    KERBEROS
  268.     if (!use_kerberos)
  269. #endif
  270.         if (fromp->sin_port >= IPPORT_RESERVED ||
  271.             fromp->sin_port < IPPORT_RESERVED/2) {
  272.             syslog(LOG_NOTICE|LOG_AUTH,
  273.                 "Connection from %s on illegal port %u",
  274.                 inet_ntoa(fromp->sin_addr),
  275.                 fromp->sin_port);
  276.             exit(1);
  277.         }
  278.  
  279.     (void) alarm(60);
  280.     port = 0;
  281.     for (;;) {
  282.         char c;
  283.         if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
  284.             if (cc < 0)
  285.                 syslog(LOG_NOTICE, "read: %m");
  286.             shutdown(0, 1+1);
  287.             exit(1);
  288.         }
  289.         if (c== 0)
  290.             break;
  291.         port = port * 10 + c - '0';
  292.     }
  293.  
  294.     (void) alarm(0);
  295.     if (port != 0) {
  296.         int lport = IPPORT_RESERVED - 1;
  297.         s = rresvport(&lport);
  298.         if (s < 0) {
  299.             syslog(LOG_ERR, "can't get stderr port: %m");
  300.             exit(1);
  301.         }
  302. #ifdef    KERBEROS
  303.         if (!use_kerberos)
  304. #endif
  305.             if (port >= IPPORT_RESERVED) {
  306.                 syslog(LOG_ERR, "2nd port not reserved\n");
  307.                 exit(1);
  308.             }
  309.         fromp->sin_port = htons(port);
  310.         if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
  311.             syslog(LOG_INFO, "connect second port %d: %m", port);
  312.             exit(1);
  313.         }
  314.     }
  315.  
  316. #ifdef    KERBEROS
  317.     if (vacuous) {
  318.         error("rshd: remote host requires Kerberos authentication\n");
  319.         exit(1);
  320.     }
  321. #endif
  322.  
  323. #ifdef notdef
  324.     /* from inetd, socket is already on 0, 1, 2 */
  325.     dup2(f, 0);
  326.     dup2(f, 1);
  327.     dup2(f, 2);
  328. #endif
  329.     errorstr = NULL;
  330.     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
  331.         fromp->sin_family);
  332.     if (hp) {
  333.         /*
  334.          * If name returned by gethostbyaddr is in our domain,
  335.          * attempt to verify that we haven't been fooled by someone
  336.          * in a remote net; look up the name and check that this
  337.          * address corresponds to the name.
  338.          */
  339.         hostname = hp->h_name;
  340. #ifdef    KERBEROS
  341.         if (!use_kerberos)
  342. #endif
  343.         if (check_all || local_domain(hp->h_name)) {
  344.             char *remotehost = alloca (strlen (hp->h_name) + 1);
  345.             if (! remotehost)
  346.                 errorstr = "Out of memory\n";
  347.             else {
  348.                 strcpy(remotehost, hp->h_name);
  349.                 errorhost = remotehost;
  350.                 hp = gethostbyname(remotehost);
  351.                 if (hp == NULL) {
  352.                     syslog(LOG_INFO,
  353.                         "Couldn't look up address for %s",
  354.                         remotehost);
  355.                     errorstr =
  356.                    "Couldn't look up address for your host (%s)\n";
  357.                     hostname = inet_ntoa(fromp->sin_addr);
  358.                 } else for (; ; hp->h_addr_list++) {
  359.                     if (hp->h_addr_list[0] == NULL) {
  360.                         syslog(LOG_NOTICE,
  361.                      "Host addr %s not listed for host %s",
  362.                             inet_ntoa(fromp->sin_addr),
  363.                             hp->h_name);
  364.                         errorstr =
  365.                           "Host address mismatch for %s\n";
  366.                         hostname = inet_ntoa(fromp->sin_addr);
  367.                         break;
  368.                     }
  369.                     if (!bcmp(hp->h_addr_list[0],
  370.                         (caddr_t)&fromp->sin_addr,
  371.                         sizeof(fromp->sin_addr))) {
  372.                         hostname = hp->h_name;
  373.                         break;
  374.                     }
  375.                 }
  376.             }
  377.         }
  378.     } else
  379.         errorhost = hostname = inet_ntoa(fromp->sin_addr);
  380.  
  381. #ifdef    KERBEROS
  382.     if (use_kerberos) {
  383.         kdata = (AUTH_DAT *) authbuf;
  384.         ticket = (KTEXT) tickbuf;
  385.         authopts = 0L;
  386.         strcpy(instance, "*");
  387.         version[VERSION_SIZE - 1] = '\0';
  388. #ifdef CRYPT
  389.         if (doencrypt) {
  390.             struct sockaddr_in local_addr;
  391.             rc = sizeof(local_addr);
  392.             if (getsockname(0, (struct sockaddr *)&local_addr,
  393.                 &rc) < 0) {
  394.                 syslog(LOG_ERR, "getsockname: %m");
  395.                 error("rlogind: getsockname: %m");
  396.                 exit(1);
  397.             }
  398.             authopts = KOPT_DO_MUTUAL;
  399.             rc = krb_recvauth(authopts, 0, ticket,
  400.                 "rcmd", instance, &fromaddr,
  401.                 &local_addr, kdata, "", schedule,
  402.                 version);
  403.             des_set_key(kdata->session, schedule);
  404.         } else
  405. #endif
  406.             rc = krb_recvauth(authopts, 0, ticket, "rcmd",
  407.                 instance, &fromaddr,
  408.                 (struct sockaddr_in *) 0,
  409.                 kdata, "", (bit_64 *) 0, version);
  410.         if (rc != KSUCCESS) {
  411.             error("Kerberos authentication failure: %s\n",
  412.                   krb_err_txt[rc]);
  413.             exit(1);
  414.         }
  415.     } else
  416. #endif
  417.         remuser = getstr ("remuser");
  418.  
  419.     locuser = getstr ("locuser");
  420.     cmdbuf = getstr ("command");
  421.  
  422.     setpwent();
  423.     pwd = getpwnam(locuser);
  424.     if (pwd == NULL) {
  425.         syslog(LOG_INFO|LOG_AUTH,
  426.             "%s@%s as %s: unknown login. cmd='%.80s'",
  427.             remuser, hostname, locuser, cmdbuf);
  428.         if (errorstr == NULL)
  429.             errorstr = "Login incorrect.\n";
  430.         goto fail;
  431.     }
  432.     if (chdir(pwd->pw_dir) < 0) {
  433.         (void) chdir("/");
  434. #ifdef notdef
  435.         syslog(LOG_INFO|LOG_AUTH,
  436.             "%s@%s as %s: no home directory. cmd='%.80s'",
  437.             remuser, hostname, locuser, cmdbuf);
  438.         error("No remote directory.\n");
  439.         exit(1);
  440. #endif
  441.     }
  442.  
  443. #ifdef    KERBEROS
  444.     if (use_kerberos) {
  445.         if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
  446.             if (kuserok(kdata, locuser) != 0) {
  447.                 syslog(LOG_INFO|LOG_AUTH,
  448.                     "Kerberos rsh denied to %s.%s@%s",
  449.                     kdata->pname, kdata->pinst, kdata->prealm);
  450.                 error("Permission denied.\n");
  451.                 exit(1);
  452.             }
  453.         }
  454.     } else
  455. #endif
  456.  
  457.         if (errorstr ||
  458.             pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
  459.             iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
  460.             remuser, locuser) < 0) {
  461.             if (__rcmd_errstr)
  462.                 syslog(LOG_INFO|LOG_AUTH,
  463.                 "%s@%s as %s: permission denied (%s). cmd='%.80s'",
  464.                     remuser, hostname, locuser, __rcmd_errstr,
  465.                     cmdbuf);
  466.             else
  467.                 syslog(LOG_INFO|LOG_AUTH,
  468.                 "%s@%s as %s: permission denied. cmd='%.80s'",
  469.                     remuser, hostname, locuser, cmdbuf);
  470. fail:
  471.             if (errorstr == NULL)
  472.                 errorstr = "Permission denied.\n";
  473.             error(errorstr, errorhost);
  474.             exit(1);
  475.         }
  476.  
  477.     if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
  478.         error("Logins currently disabled.\n");
  479.         exit(1);
  480.     }
  481.  
  482.     (void) write(STDERR_FILENO, "\0", 1);
  483.     sent_null = 1;
  484.  
  485.     if (port) {
  486.         if (pipe(pv) < 0) {
  487.             error("Can't make pipe.\n");
  488.             exit(1);
  489.         }
  490. #ifdef CRYPT
  491. #ifdef KERBEROS
  492.         if (doencrypt) {
  493.             if (pipe(pv1) < 0) {
  494.                 error("Can't make 2nd pipe.\n");
  495.                 exit(1);
  496.             }
  497.             if (pipe(pv2) < 0) {
  498.                 error("Can't make 3rd pipe.\n");
  499.                 exit(1);
  500.             }
  501.         }
  502. #endif
  503. #endif
  504.         pid = fork();
  505.         if (pid == -1)  {
  506.             error("Can't fork; try again.\n");
  507.             exit(1);
  508.         }
  509.         if (pid) {
  510. #ifdef CRYPT
  511. #ifdef KERBEROS
  512.             if (doencrypt) {
  513.                 static char msg[] = SECURE_MESSAGE;
  514.                 (void) close(pv1[1]);
  515.                 (void) close(pv2[1]);
  516.                 des_write(s, msg, sizeof(msg) - 1);
  517.  
  518.             } else
  519. #endif
  520. #endif
  521.             {
  522.                 (void) close(0);
  523.                 (void) close(1);
  524.             }
  525.             (void) close(2);
  526.             (void) close(pv[1]);
  527.  
  528.             FD_ZERO(&readfrom);
  529.             FD_SET(s, &readfrom);
  530.             FD_SET(pv[0], &readfrom);
  531.             if (pv[0] > s)
  532.                 nfd = pv[0];
  533.             else
  534.                 nfd = s;
  535. #ifdef CRYPT
  536. #ifdef KERBEROS
  537.             if (doencrypt) {
  538.                 FD_ZERO(&writeto);
  539.                 FD_SET(pv2[0], &writeto);
  540.                 FD_SET(pv1[0], &readfrom);
  541.  
  542.                 nfd = MAX(nfd, pv2[0]);
  543.                 nfd = MAX(nfd, pv1[0]);
  544.             } else
  545. #endif
  546. #endif
  547.                 ioctl(pv[0], FIONBIO, (char *)&one);
  548.  
  549.             /* should set s nbio! */
  550.             nfd++;
  551.             do {
  552.                 ready = readfrom;
  553. #ifdef CRYPT
  554. #ifdef KERBEROS
  555.                 if (doencrypt) {
  556.                     wready = writeto;
  557.                     if (select(nfd, &ready,
  558.                         &wready, (fd_set *) 0,
  559.                         (struct timeval *) 0) < 0)
  560.                         break;
  561.                 } else
  562. #endif
  563. #endif
  564.                     if (select(nfd, &ready, (fd_set *)0,
  565.                       (fd_set *)0, (struct timeval *)0) < 0)
  566.                         break;
  567.                 if (FD_ISSET(s, &ready)) {
  568.                     int    ret;
  569. #ifdef CRYPT
  570. #ifdef KERBEROS
  571.                     if (doencrypt)
  572.                         ret = des_read(s, &sig, 1);
  573.                     else
  574. #endif
  575. #endif
  576.                         ret = read(s, &sig, 1);
  577.                     if (ret <= 0)
  578.                         FD_CLR(s, &readfrom);
  579.                     else
  580.                         killpg(pid, sig);
  581.                 }
  582.                 if (FD_ISSET(pv[0], &ready)) {
  583.                     errno = 0;
  584.                     cc = read(pv[0], buf, sizeof(buf));
  585.                     if (cc <= 0) {
  586.                         shutdown(s, 1+1);
  587.                         FD_CLR(pv[0], &readfrom);
  588.                     } else {
  589. #ifdef CRYPT
  590. #ifdef KERBEROS
  591.                         if (doencrypt)
  592.                             (void)
  593.                               des_write(s, buf, cc);
  594.                         else
  595. #endif
  596. #endif
  597.                             (void)
  598.                               write(s, buf, cc);
  599.                     }
  600.                 }
  601. #ifdef CRYPT
  602. #ifdef KERBEROS
  603.                 if (doencrypt && FD_ISSET(pv1[0], &ready)) {
  604.                     errno = 0;
  605.                     cc = read(pv1[0], buf, sizeof(buf));
  606.                     if (cc <= 0) {
  607.                         shutdown(pv1[0], 1+1);
  608.                         FD_CLR(pv1[0], &readfrom);
  609.                     } else
  610.                         (void) des_write(STDOUT_FILENO,
  611.                             buf, cc);
  612.                 }
  613.  
  614.                 if (doencrypt && FD_ISSET(pv2[0], &wready)) {
  615.                     errno = 0;
  616.                     cc = des_read(STDIN_FILENO,
  617.                         buf, sizeof(buf));
  618.                     if (cc <= 0) {
  619.                         shutdown(pv2[0], 1+1);
  620.                         FD_CLR(pv2[0], &writeto);
  621.                     } else
  622.                         (void) write(pv2[0], buf, cc);
  623.                 }
  624. #endif
  625. #endif
  626.  
  627.             } while (FD_ISSET(s, &readfrom) ||
  628. #ifdef CRYPT
  629. #ifdef KERBEROS
  630.                 (doencrypt && FD_ISSET(pv1[0], &readfrom)) ||
  631. #endif
  632. #endif
  633.                 FD_ISSET(pv[0], &readfrom));
  634.             exit(0);
  635.         }
  636.         setpgrp(0, getpid());
  637.         (void) close(s);
  638.         (void) close(pv[0]);
  639. #ifdef CRYPT
  640. #ifdef KERBEROS
  641.         if (doencrypt) {
  642.             close(pv1[0]); close(pv2[0]);
  643.             dup2(pv1[1], 1);
  644.             dup2(pv2[1], 0);
  645.             close(pv1[1]);
  646.             close(pv2[1]);
  647.         }
  648. #endif
  649. #endif
  650.         dup2(pv[1], 2);
  651.         close(pv[1]);
  652.     }
  653.     if (*pwd->pw_shell == '\0')
  654.         pwd->pw_shell = _PATH_BSHELL;
  655. #if    BSD > 43
  656.     if (setlogin(pwd->pw_name) < 0)
  657.         syslog(LOG_ERR, "setlogin() failed: %m");
  658. #endif
  659.     (void) setgid((gid_t)pwd->pw_gid);
  660.     initgroups(pwd->pw_name, pwd->pw_gid);
  661.     (void) setuid((uid_t)pwd->pw_uid);
  662.     environ = envinit;
  663.     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  664.     strcat(path, _PATH_DEFPATH);
  665.     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  666.     strncat(username, pwd->pw_name, sizeof(username)-6);
  667.     cp = strrchr(pwd->pw_shell, '/');
  668.     if (cp)
  669.         cp++;
  670.     else
  671.         cp = pwd->pw_shell;
  672.     endpwent();
  673.     if (log_success || pwd->pw_uid == 0) {
  674. #ifdef    KERBEROS
  675.         if (use_kerberos)
  676.             syslog(LOG_INFO|LOG_AUTH,
  677.             "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
  678.             kdata->pname, kdata->pinst, kdata->prealm,
  679.             hostname, locuser, cmdbuf);
  680.         else
  681. #endif
  682.             syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
  683.             remuser, hostname, locuser, cmdbuf);
  684.     }
  685.     execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
  686.     perror(pwd->pw_shell);
  687.     exit(1);
  688. }
  689.  
  690. /*
  691.  * Report error to client.  Note: can't be used until second socket has
  692.  * connected to client, or older clients will hang waiting for that
  693.  * connection first.
  694.  */
  695. #if __STDC__
  696. #include <stdarg.h>
  697. #else
  698. #include <varargs.h>
  699. #endif
  700.  
  701. void
  702. #if __STDC__
  703. error(const char *fmt, ...)
  704. #else
  705. error(fmt, va_alist)
  706.     char *fmt;
  707.         va_dcl
  708. #endif
  709. {
  710.     va_list ap;
  711.     int len;
  712.     char *bp, buf[BUFSIZ];
  713. #if __STDC__
  714.     va_start(ap, fmt);
  715. #else
  716.     va_start(ap);
  717. #endif
  718.     bp = buf;
  719.     if (sent_null == 0) {
  720.         *bp++ = 1;
  721.         len = 1;
  722.     } else
  723.         len = 0;
  724.     (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap);
  725.     (void)write(STDERR_FILENO, buf, len + strlen(bp));
  726. }
  727.  
  728. char *
  729. getstr(err)
  730.     char *err;
  731. {
  732.     size_t buf_len = 100;
  733.     char *buf = malloc (buf_len), *end = buf;
  734.  
  735.     if (! buf) {
  736.         error ("Out of space reading %s\n", err);
  737.         exit (1);
  738.     }
  739.  
  740.     do {
  741.         /* Oh this is efficient, oh yes.  [But what can be done?] */
  742.         int rd = read(STDIN_FILENO, end, 1);
  743.         if (rd <= 0) {
  744.             if (rd == 0)
  745.                 error ("EOF reading %s\n", err);
  746.             else
  747.                 perror (err);
  748.             exit(1);
  749.         }
  750.  
  751.         end += rd;
  752.         if ((buf + buf_len - end) < (buf_len >> 3)) {
  753.             /* Not very much room left in our buffer, grow it. */
  754.             size_t end_offs = end - buf;
  755.             buf_len += buf_len;
  756.             buf = realloc (buf, buf_len);
  757.             if (! buf) {
  758.                 error ("Out of space reading %s\n", err);
  759.                 exit (1);
  760.             }
  761.             end = buf + end_offs;
  762.         }
  763.     } while (*(end - 1));
  764.  
  765.     return buf;
  766. }
  767.  
  768. /*
  769.  * Check whether host h is in our local domain,
  770.  * defined as sharing the last two components of the domain part,
  771.  * or the entire domain part if the local domain has only one component.
  772.  * If either name is unqualified (contains no '.'),
  773.  * assume that the host is local, as it will be
  774.  * interpreted as such.
  775.  */
  776. int
  777. local_domain(h)
  778.     char *h;
  779. {
  780.     extern char *localhost ();
  781.     char *hostname = localhost ();
  782.  
  783.     if (! hostname)
  784.         return 0;
  785.     else {
  786.         int is_local = 0;
  787.         char *p1 = topdomain (hostname);
  788.         char *p2 = topdomain (h);
  789.  
  790.         if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
  791.             is_local = 1;
  792.  
  793.         free (hostname);
  794.  
  795.         return is_local;
  796.     }
  797. }
  798.  
  799. char *
  800. topdomain(h)
  801.     char *h;
  802. {
  803.     char *p, *maybe = NULL;
  804.     int dots = 0;
  805.  
  806.     for (p = h + strlen(h); p >= h; p--) {
  807.         if (*p == '.') {
  808.             if (++dots == 2)
  809.                 return (p);
  810.             maybe = p;
  811.         }
  812.     }
  813.     return (maybe);
  814. }
  815.  
  816. void
  817. usage()
  818. {
  819.  
  820.     syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
  821.     exit(2);
  822. }
  823.